#include "BaseLayer.h"
/*******************************************************************************/
/*************** Header *****************************/
#define UDP_HEADER_SIZE			8


#define RIP_PORTION_SIZE		20
#define RIP_MAX_COUNT			25
#define RIP_DATA_SIZE			RIP_PORTION_SIZE * RIP_MAX_COUNT
#define RIP_MAX_SIZE			RIP_DATA_SIZE + UDP_HEADER_SIZE

typedef struct _PseudoHeader
{
	unsigned int	SourceAddress;
	unsigned int	DestinationAddress;
	unsigned char	Zeros;
	unsigned char	PTCL;
	unsigned short	Length;
}PseudoHeader;


unsigned long CalculateChecksum(unsigned short *usBuf, int iSize)
{
	unsigned long usChecksum=0;

	while(iSize>1)
	{
		usChecksum += *usBuf;
		iSize -= sizeof(unsigned short);
	}

	if(iSize)
		usChecksum += *(unsigned char*)usBuf;

	//Complete the calculations
	usChecksum =(usChecksum >> 16 ) + (usChecksum & 0xffff);
	usChecksum += (usChecksum >> 16);

	//return the value (inversed)
	return (unsigned short)(~usChecksum);
}

unsigned short CalculatePseudoChecksum(char *buf, int BufLength, LPCSTR lpDestinationAddress,
									   LPCSTR lpSourceAddress, int iPacketLength)
{
	//Calculate the checksum
	PseudoHeader *lpPseudo;
	lpPseudo = new PseudoHeader;

	lpPseudo->DestinationAddress = inet_addr(lpDestinationAddress);
	lpPseudo->SourceAddress = inet_addr(lpSourceAddress);
	
	lpPseudo->Zeros = 0;
	lpPseudo->PTCL = 17; //UDP protocol number
	lpPseudo->Length = htons(iPacketLength);

	//Calculate checksum of all
	int iTotalLength;
	int PseudoHeaderLength = 12;

	iTotalLength = PseudoHeaderLength + iPacketLength;
	char* tmpBuf;
	tmpBuf = new char[iTotalLength];

	//Copy pseudo
	memcpy(tmpBuf, lpPseudo, PseudoHeaderLength);

	//Copy header

	memcpy(tmpBuf+PseudoHeaderLength,buf,iPacketLength);

	//Calculate the checksum
	unsigned short usChecksum;
	usChecksum = CalculateChecksum((unsigned short*)tmpBuf, iTotalLength);

	//Delete all
	delete tmpBuf;
	delete lpPseudo;

	//return checksum
	return usChecksum;
}

/*************************************************************************************/
class CUDPLayer :public CBaseLayer
{
private:
	void ResetHeader();
#pragma pack(1)
	typedef struct _UDP_HEADER {
		USHORT	uh_sport;	/* source port*/
		USHORT	uh_dport;	/*destination port*/
		USHORT	uh_ulen;	/*udp length*/
		USHORT	uh_sum;		/*udp checksum*/
		UCHAR	udp_data[RIP_DATA_SIZE]; /* RIP Table */
	}UDP_HEADER, *PUDP_HEADER;
#pragma pop()
public:
	BOOL	Receive(unsigned char* ppayload);
	BOOL	Send(unsigned char* ppayload, int nlength);
	
	CUDPLayer(char *pName);
	CUDPLayer();

	void	SetUDPDstPort(USHORT uh_dstPort);
	void	SetUDPSrcPort(USHORT uh_srcPort);
	void	SetUDPLength(USHORT uh_ulen);
	void	SetUDPCheckSum(USHORT uh_sum);

	USHORT	GetUDPDstPort();
	USHORT	GetUDPSrcPort();
	USHORT	GetUDPLength();
	USHORT	GetUDPCheckSum();
protected:
	UDP_HEADER m_udp_header;
	
};
